/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
 * Global Trust Authority is licensed under the Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *     http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
 * PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

use std::collections::HashMap;

use openssl::hash::{hash, MessageDigest};
use serde::{Deserialize, Serialize};

use crate::constants::VERIFIER_DEVELOPER;
use crate::entities::attest_request::Measurement;
use crate::entities::token::{PolicyInfo, PolicyMatchedInfo};
use crate::entities::token::token_trait::{AttesterResult, Token, TokenType};

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct EarToken {
    pub matched_policy: Vec<PolicyMatchedInfo>,
    pub unmatched_policy: Vec<PolicyMatchedInfo>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub ueid: Option<String>,
    #[serde(rename = "ear.verifier-id")]
    pub ear_verifier_id: EarTokenVerifierId,
    #[serde(skip_serializing_if = "Option::is_none")]
    #[serde(rename = "ear.raw-evidence")]
    pub ear_raw_evidence: Option<serde_json::Value>,
    pub submods: Vec<EarSubmodResult>,
}

impl EarToken {
    pub fn new() -> Self {
        Self {
            ear_verifier_id: EarTokenVerifierId {
                developer: VERIFIER_DEVELOPER.to_string(),
                version: "v1.0.0".to_string(),
            },
            matched_policy: Vec::new(),
            unmatched_policy: Vec::new(),
            ueid: None,
            ear_raw_evidence: None,
            submods: Vec::new(),
        }
    }

    pub fn get_ueid(attester_data: &HashMap<String, EarAttesterResult>) -> Option<String> {
        for (_, ear_attester_result) in attester_data {
            if let Some(raw_evidence) = &(ear_attester_result.ear_gta_annotated_evidence) {
                if let Some(ueid) = raw_evidence.get("ueid") {
                    return Some(ueid.to_string());
                }
            }
        }
        None
    }
    
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct EarTokenVerifierId {
    pub developer: String,
    pub version: String,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct EarSubmodResult {
    #[serde(flatten)]
    pub ear_attester_results: HashMap<String, EarAttesterResult>,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct EarAttesterResult {
    #[serde(rename = "ear.status")]
    pub ear_status: String,
    #[serde(rename = "ear.trustworthiness-vector")]
    #[serde(skip_serializing_if = "Option::is_none")]
    pub ear_trustworthiness_vector: Option<Vec<EarTrustworthinessVector>>,
    #[serde(rename = "ear.appraisal-policy-id")]
    #[serde(skip_serializing_if = "Option::is_none")]
    pub ear_appraisal_policy_id: Option<String>,
    #[serde(rename = "ear.gta-annotated-evidence")]
    #[serde(skip_serializing_if = "Option::is_none")]
    pub ear_gta_annotated_evidence: Option<serde_json::Value>,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct EarTrustworthinessVector {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub executables: Option<i32>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub hardware: Option<i32>,
}

impl EarToken {
    fn determine_ear_status(policy_info: &[PolicyInfo], verify_results: &[bool]) -> &'static str {
        if policy_info.is_empty() {
            "none"
        } else if verify_results.iter().all(|&x| x) {
            "affirming"
        } else {
            "contarindicated"
        }
    }

    fn extract_trustworthiness_vector(evidence: &serde_json::Value) -> EarTrustworthinessVector {
        let mut trustworthiness_vector = EarTrustworthinessVector { 
            hardware: None, 
            executables: None 
        };
        
        if let Some(tv) = evidence.get("ear_trustworthiness_vector") {
            if let Some(hardware_value) = tv.get("hardware") {
                if let Some(hardware) = hardware_value.as_i64() {
                    trustworthiness_vector.hardware = Some(hardware as i32);
                }
            }
            
            if let Some(executables_value) = tv.get("executables") {
                if let Some(executables) = executables_value.as_i64() {
                    trustworthiness_vector.executables = Some(executables as i32);
                }
            }
        }
        
        trustworthiness_vector
    }

    fn process_raw_evidence(
        raw_evidence: &Option<serde_json::Value>
    ) -> (Option<Vec<EarTrustworthinessVector>>, Option<serde_json::Value>) {
        match raw_evidence {
            Some(evidence) => {
                let trustworthiness_vector = Self::extract_trustworthiness_vector(evidence);
                let annotated_evidence = evidence.get("annotated_evidence").cloned();
                (Some(vec![trustworthiness_vector]), annotated_evidence)
            }
            None => (None, None)
        }
    }

    fn calculate_sha256(content: &str) -> String {
        match hash(MessageDigest::sha256(), content.as_bytes()) {
            Ok(digest) => {
                digest.iter().map(|b| format!("{:02x}", b)).collect::<String>()
            },
            Err(_) => String::new(),
        }
    }

    fn process_policy_matches(&mut self, policy_info: &[PolicyInfo]) {
        for policy in policy_info {
            let policy_matched_info = PolicyMatchedInfo {
                id: policy.appraisal_policy_id.clone(),
                version: policy.policy_version,
                sha256: Self::calculate_sha256(&policy.policy_content),
            };
            
            if policy.policy_matched {
                self.matched_policy.push(policy_matched_info);
            } else {
                self.unmatched_policy.push(policy_matched_info);
            }
        }
    }
}

impl Token for EarToken {
    fn create_evidence_response(
        &mut self,
        verify_results: Vec<bool>,
        raw_evidence: Option<serde_json::Value>,
        policy_info: Vec<PolicyInfo>,
    ) -> AttesterResult {
        let appraisal_policy_id =
            policy_info.first().map(|policy| policy.appraisal_policy_id.clone());

        let ear_status = Self::determine_ear_status(&policy_info, &verify_results);
        let (ear_trustworthiness_vector, ear_gta_annotated_evidence) = 
            Self::process_raw_evidence(&raw_evidence);
        
        self.process_policy_matches(&policy_info);

        AttesterResult::Ear(EarAttesterResult {
            ear_status: ear_status.to_string(),
            ear_trustworthiness_vector,
            ear_gta_annotated_evidence,
            ear_appraisal_policy_id: appraisal_policy_id,
        })
    }

    fn create_attestation_response(
        &self,
        evidence_token_responses: &HashMap<String, AttesterResult>,
        _nonce_type: &str,
        _nonce: &Option<String>,
        measurement: &Measurement,
    ) -> TokenType {
        let mut ear_submods = Vec::new();
        let mut ear_attester_results = HashMap::new();
        
        for (key, value) in evidence_token_responses {
            if let AttesterResult::Ear(ear_result) = value {
                ear_attester_results.insert(key.clone(), ear_result.clone());
            }
        }
        let ueid = match Self::get_ueid(&ear_attester_results) {
            Some(ueid) => ueid,
            None => measurement.node_id.clone()
        };
        
        if !ear_attester_results.is_empty() {
            ear_submods.push(EarSubmodResult {
                ear_attester_results,
            });
        }

        TokenType::Ear(EarToken {
            ear_verifier_id: EarTokenVerifierId {
                developer: VERIFIER_DEVELOPER.to_string(),
                version: "v1.0.0".to_string(),
            },
            matched_policy: self.matched_policy.clone(),
            unmatched_policy: self.unmatched_policy.clone(),
            ueid: Some(ueid),
            ear_raw_evidence: None,
            submods: ear_submods,
        })
    }
}